""" 
内置异常

在 Python 中，所有异常必须为一个派生自 BaseException 的类的实例。 

用户代码可以引发内置异常。
这可被用于测试异常处理程序或报告错误条件，“就像” 在解释器引发了相同异常的情况时一样；但是请注意，没有任何机制能防止用户代码引发不适当的错误。

内置异常类可以被子类化以定义新的异常；鼓励程序员从 Exception 类或它的某个子类而不是从 BaseException 来派生新的异常。
关于定义异常的更多信息可以在 Python 教程的 用户自定义异常 部分查看。



异常层次结构

内置异常的类层级结构如下：
https://docs.python.org/zh-cn/3.8/library/exceptions.html

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception                    所有内置的非系统退出类异常都派生自此类。 所有用户自定义异常也应当派生自此类。
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError         此基类用于派生针对各种算术类错误而引发的内置异常: OverflowError, ZeroDivisionError, FloatingPointError。
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError             当与 缓冲区 相关的操作无法执行时将被引发。
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError              此基类用于派生当映射或序列所使用的键或索引无效时引发的异常: IndexError, KeyError。 这可以通过 codecs.lookup() 来直接引发。
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

"""

""" 
try:
  num1 = int(input("请输入第一个数字："))
  num2 = int(input("请输入第二个数字："))

  res = num1 / num2
  print("两个数字相除的结果是：", res)

except Exception as e:
  print("报错，请注意输入。", e) 
"""

# 自定义一个异常类
""" 
# 自定义一个异常类 覆盖之前的异常类
# 类要用class  不要写成def
"""
class LessThanZeroException(Exception):
  def __init__(self, message):
    self.message = message

  def __str__(self):
    return self.message

""" 
当引发一个新的异常（而不是简单地使用 raise 来重新引发 当前在处理的异常）时，隐式的异常上下文可以通过使用带有 raise 的 from 子句来补充一个显式的原因:
raise new_exc from original_exc

跟在 from 之后一表达式必须为一个异常或 None。
它将在所引发的异常上被设置为 __cause__。
设置 __cause__ 还会隐式地将 __suppress_context__ 属性设为 True，这样使用 raise new_exc from None 可以有效地将旧异常替换为新异常来显示其目的 (例如将 KeyError 转换为 AttributeError)，同时让旧异常在 __context__ 中保持可用状态以便在调试时进行内省。
"""

""" 
try:
  num1 = int(input("请输入第一个数字："))
  num2 = int(input("请输入第二个数字："))

  if num1 < 0 or num2 < 0:
    raise LessThanZeroException("请输入大于0的数字")

  res = num1 / num2
  print("两个数字相除的结果是：", res)

except Exception as e:
  print("捉到了一个bug：", e)  
"""

# else处理  在try语句执行成功后，才会执行的语句
try:
  num1 = int(input("请输入第一个数字："))
  num2 = int(input("请输入第二个数字："))

  if num1 < 0 or num2 < 0:
    raise LessThanZeroException("请输入大于0的数字")

except Exception as e:
  print("捉到了一个bug：", e)

else:
  res = num1 / num2
  print("两个数字相除的结果是：", res)

# finally处理   无论成功还是异常  都会输入的语句
try:
  num1 = int(input("请输入第一个数字："))
  num2 = int(input("请输入第二个数字："))

  if num1 < 0 or num2 < 0:
    raise LessThanZeroException("请输入大于0的数字")

except Exception as e:
  print("捉到了一个bug：", e)

else:
  res = num1 / num2
  print("两个数字相除的结果是：", res)

finally:
  print("感谢使用除法程序。")
